package scatter.moment.rest.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.Assert;
import scatter.comment.pojo.subject.po.CommentSubject;
import scatter.comment.rest.subject.mapstruct.CommentSubjectMapStruct;
import scatter.comment.rest.subject.service.ICommentSubjectService;
import scatter.common.LoginUser;
import scatter.common.pojo.form.BasePageQueryForm;
import scatter.moment.pojo.form.MomentAvailablePageQueryForm;
import scatter.moment.pojo.param.MomentPublishParam;
import scatter.moment.pojo.po.Moment;
import scatter.moment.pojo.po.MomentStar;
import scatter.moment.pojo.vo.AvailableMomentVo;
import scatter.moment.pojo.vo.MomentVo;
import scatter.moment.rest.componentext.MomentAvailableExtProvider;
import scatter.moment.rest.componentext.MomentPublishListener;
import scatter.moment.rest.mapper.MomentMapper;
import scatter.moment.rest.mapstruct.MomentMapStruct;
import scatter.moment.rest.mapstruct.MomentStarMapStruct;
import scatter.moment.rest.service.IMomentPicService;
import scatter.moment.rest.service.IMomentService;
import scatter.common.rest.service.IBaseAddUpdateQueryFormServiceImpl;
import org.springframework.stereotype.Service;
import scatter.moment.pojo.form.MomentAddForm;
import scatter.moment.pojo.form.MomentUpdateForm;
import scatter.moment.pojo.form.MomentPageQueryForm;
import org.springframework.transaction.annotation.Transactional;
import scatter.moment.rest.service.IMomentStarService;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

/**
 * <p>
 * 时刻动态表 服务实现类
 * </p>
 *
 * @author yw
 * @since 2021-02-09
 */
@Service
@Transactional
public class MomentServiceImpl extends IBaseAddUpdateQueryFormServiceImpl<MomentMapper, Moment, MomentAddForm, MomentUpdateForm, MomentPageQueryForm> implements IMomentService {

    @Qualifier("commonDbTaskExecutor")
    @Autowired
    private ExecutorService executorService;

    @Autowired
    private IMomentPicService iMomentPicService;

    @Autowired
    private IMomentStarService momentStarService;

    @Autowired
    private ICommentSubjectService iCommentSubjectService;


    @Autowired(required = false)
    private List<MomentAvailableExtProvider> momentAvailableExtProviders;

    @Autowired(required = false)
    private List<MomentPublishListener> momentPublishListeners;

    @Override
    public void preAdd(MomentAddForm addForm,Moment po) {
        super.preAdd(addForm,po);

    }

    @Override
    public void preUpdate(MomentUpdateForm updateForm,Moment po) {
        super.preUpdate(updateForm,po);

    }

    @Override
    public IPage<AvailableMomentVo> listAvailablePage(MomentAvailablePageQueryForm pageQueryForm,String loginUserId) throws InterruptedException {
        Page<Moment> page = page(convertPage(pageQueryForm), Wrappers.<Moment>lambdaQuery()
                .eq(Moment::getIsDisabled, false)
                .eq(!isStrEmpty(pageQueryForm.getGroupFlag()), Moment::getGroupFlag, pageQueryForm.getGroupFlag())
                .orderByDesc(Moment::getTimeAt).orderByDesc(Moment::getId));

        IPage<AvailableMomentVo> momentVoIPage = MomentMapStruct.INSTANCE.pagePoToAvailableMomentVo(page);

        int num = 3;
        if (!isEmpty(momentAvailableExtProviders)) {
            num += momentAvailableExtProviders.size();
        }

        // 下面是添加异步执行，加快提高性能
        CountDownLatch countDownLatch = new CountDownLatch(num);
        executorService.execute(()->{
            try {
                fillHasStared(momentVoIPage.getRecords(),loginUserId);
            } finally {
                countDownLatch.countDown();
            }
        });
        executorService.execute(()->{
            try {
                fillLatestMomentStar(momentVoIPage.getRecords(),10);
            } finally {
                countDownLatch.countDown();
            }
        });
        executorService.execute(()->{
            try {
                fillLatestCommentSubject(momentVoIPage.getRecords(),5,pageQueryForm.getGroupFlag());
            } finally {
                countDownLatch.countDown();
            }
        });
        if (!isEmpty(momentAvailableExtProviders)) {
            for (MomentAvailableExtProvider momentAvailableExtProvider : momentAvailableExtProviders) {
                executorService.execute(()->{
                    try{
                        momentAvailableExtProvider.provideMoment(momentVoIPage.getRecords());
                    }finally {
                        countDownLatch.countDown();
                    }
                });
            }
        }
        countDownLatch.await();

        return momentVoIPage;
    }

    @Override
    public IPage<AvailableMomentVo> listAvailablePageByUserId(MomentAvailablePageQueryForm pageQueryForm, String loginUserId) throws InterruptedException {
        Assert.hasText(loginUserId,"loginUserId 不能为空");
        Page<Moment> page = page(convertPage(pageQueryForm), Wrappers.<Moment>lambdaQuery()
                .eq(Moment::getIsDisabled, false)
                .eq(Moment::getOwnerUserId,loginUserId)
                .eq(!isStrEmpty(pageQueryForm.getGroupFlag()), Moment::getGroupFlag, pageQueryForm.getGroupFlag())
                .orderByDesc(Moment::getTimeAt).orderByDesc(Moment::getId));

        IPage<AvailableMomentVo> momentVoIPage = MomentMapStruct.INSTANCE.pagePoToAvailableMomentVo(page);

        int num = 3;
        if (!isEmpty(momentAvailableExtProviders)) {
            num += momentAvailableExtProviders.size();
        }

        // 下面是添加异步执行，加快提高性能
        CountDownLatch countDownLatch = new CountDownLatch(num);
        executorService.execute(()->{
            try {
                fillHasStared(momentVoIPage.getRecords(),loginUserId);
            } finally {
                countDownLatch.countDown();
            }
        });
        executorService.execute(()->{
            try {
                fillLatestMomentStar(momentVoIPage.getRecords(),10);
            } finally {
                countDownLatch.countDown();
            }
        });
        executorService.execute(()->{
            try {
                fillLatestCommentSubject(momentVoIPage.getRecords(),5,pageQueryForm.getGroupFlag());
            } finally {
                countDownLatch.countDown();
            }
        });
        if (!isEmpty(momentAvailableExtProviders)) {
            for (MomentAvailableExtProvider momentAvailableExtProvider : momentAvailableExtProviders) {
                executorService.execute(()->{
                    try{
                        momentAvailableExtProvider.provideMoment(momentVoIPage.getRecords());
                    }finally {
                        countDownLatch.countDown();
                    }
                });
            }
        }
        countDownLatch.await();

        return momentVoIPage;
    }

    /**
     * 直充是否已点赞
     * @param momentVos
     * @param loginUserId
     */
    private void fillHasStared(List<AvailableMomentVo> momentVos, String loginUserId){
        if (isEmpty(momentVos) || loginUserId == null) {
            return;
        }
        Map<String, Boolean> stringBooleanMap = momentStarService.hasStared(momentVos.stream().map(MomentVo::getId).collect(Collectors.toList()), loginUserId);
        momentVos.forEach(item -> item.setIsMeHasStared(stringBooleanMap.get(item.getId())));

    }

    /**
     * 填充最新点赞数据
     * @param momentVos
     * @param count
     */
    private void fillLatestMomentStar(List<AvailableMomentVo> momentVos,Integer count){
        if (isEmpty(momentVos)) {
            return;
        }
        Map<String, Page<MomentStar>> stringPageMap = momentStarService.listLatestStarForPerMoment(momentVos.stream().map(MomentVo::getId).collect(Collectors.toList()), count);
        for (AvailableMomentVo item : momentVos) {
            IPage iPage = MomentStarMapStruct.INSTANCE.pagePoToVo(stringPageMap.get(item.getId()));
            item.setLatestMomentStars(iPage);
        }
    }
    /**
     * 填充评论数据
     * @param momentVos
     * @param count
     */
    private void fillLatestCommentSubject(List<AvailableMomentVo> momentVos,Integer count,String groupFlag){
        Map<String, Page<CommentSubject>> stringPageMap =
                iCommentSubjectService.listLatestCommentSubjectForPerSubject(momentVos.stream().map(MomentVo::getId).collect(Collectors.toList()), count,groupFlag);
        for (AvailableMomentVo item : momentVos) {
            IPage iPage = CommentSubjectMapStruct.INSTANCE.pagePoToVo(stringPageMap.get(item.getId()));
            item.setLatestCommentSubjects(iPage);
        }
    }
    @Override
    public Moment publish(MomentPublishParam param) {
        Moment moment = MomentMapStruct.INSTANCE.publishParamToPo(param);
        moment.setIsDisabled(false);
        moment.setCommentCount(0);
        moment.setStarCount(0);
        moment.setTimeAt(LocalDateTime.now());
        //        监听扩展
        if (!isEmpty(momentPublishListeners)) {
            for (MomentPublishListener momentPublishListener : momentPublishListeners) {
                momentPublishListener.preMomentPublish( param, moment);
            }
        }
        save(moment);
        // 添加图片
        if (!isEmpty(param.getMomentPicUrls())) {
            iMomentPicService.addPics(param.getMomentPicUrls(),moment.getId());
        }
        // 监听扩展
        if (!isEmpty(momentPublishListeners)) {
            for (MomentPublishListener momentPublishListener : momentPublishListeners) {
                momentPublishListener.postMomentPublish( param, moment);
            }
        }
        return moment;
    }
}
